﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Text;

namespace Fusters_Log_Splitter
{
    class WoWLog
    {

        private Dictionary<string, Hashtable> bosses = new Dictionary<string, Hashtable>();
        private Dictionary<string, string[]> startIDs = new Dictionary<string, string[]>();
        private Dictionary<string, string[]> contIDs = new Dictionary<string, string[]>();
        private Dictionary<string, string[]> endIDs = new Dictionary<string, string[]>();

        private int highestPercentageReached = 0;

        private string _logPath;
        private string _logFile;

        private string _outPath;
        private int _timeShift;
        private int _splitGap;
        private bool _deleteLog;

        private void WoWLogInit()
        {
            this.BuildBossHash();

            string myPrinter = "";

            foreach (string bossname in contIDs.Keys)
            {
                foreach (string actualID in contIDs[bossname])
                {
                    myPrinter += actualID;
                    myPrinter += " | ";
                }
            }

            //MessageBox.Show(myPrinter);
        }

        public WoWLog()
        {
            this.WoWLogInit();
        }

        public WoWLog(string inPath, string inFile)
        {
            _logPath = inPath;
            _logFile = inFile;
            this.WoWLogInit();
        }

        public void setOutParams(string outPath, int timeShift, int splitGap, bool deleteLog)
        {
            _outPath = outPath;
            _timeShift = timeShift;
            _splitGap = splitGap;
            _deleteLog = deleteLog;
        }

        public int LineCount()
        {
            FileStream FS = new FileStream(_logPath+"\\"+_logFile, FileMode.Open, FileAccess.Read, FileShare.Read);
            StreamReader reader = new StreamReader(FS);

            char[] buffer = new char[32 * 1024]; // Read 32K chars at a time

            int total = 1; // All files have at least one line!

            int read;
            while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
            {
                for (int i = 0; i < read; i++)
                {
                    if (buffer[i] == '\n')
                    {
                        total++;
                    }
                }
            }

            return total;
        }

        public void LogSplitTemporalThreaded(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            int currentLines = 1; 

            int totalLines = (int)LineCount();

            StreamReader sr = new StreamReader(_logPath + "\\" + _logFile);
            string str = sr.ReadLine();
            string[] dateArray = str.Split(' ');
            DateTime myDate = DateTime.Parse(dateArray[0] + "/" + DateTime.Now.Year + " " + dateArray[1]);
            DateTime myOldDate = myDate;
            DateTime myFixedDate = myDate.AddHours((double)_timeShift);

            string[] stringSeparators = new string[] { dateArray[1] };
            string[] parseArray = str.Split(stringSeparators, StringSplitOptions.None);
            string strTimeFixed = myFixedDate.ToString("M/dd HH:mm:ss.fff") + parseArray[1];


            string p = _outPath + "\\" + _logFile.Substring(0, _logFile.Length - 4) + "_" + myFixedDate.Year + "_" + myFixedDate.Month + "_" + myFixedDate.Day + "_" + myFixedDate.Hour + myFixedDate.Minute + ".txt";

            StreamWriter sw = new StreamWriter(p);
            sw.WriteLine(strTimeFixed);

            while (!sr.EndOfStream)
            {
                str = sr.ReadLine();
                dateArray = str.Split(' ');
                myDate = DateTime.Parse(dateArray[0] + "/" + DateTime.Now.Year + " " + dateArray[1]);
                myFixedDate = myDate.AddHours((double)_timeShift);

                stringSeparators = new string[] { dateArray[1] };
                parseArray = str.Split(stringSeparators, StringSplitOptions.None);
                strTimeFixed = myFixedDate.ToString("M/dd HH:mm:ss.fff") + parseArray[1];

                if (myDate > (myOldDate + new TimeSpan(0, _splitGap, 0)))
                {
                    sw.Close();

                    p = _outPath + "\\" + _logFile.Substring(0, _logFile.Length - 4) + "_" + myDate.Year + "_" + myDate.Month + "_" + myDate.Day + "_" + myDate.Hour + myDate.Minute + ".txt";
                    sw = new StreamWriter(p);
                }

                myOldDate = myDate;

                sw.WriteLine(strTimeFixed);

                currentLines = currentLines + 1;
                int percentComplete = (int)((float)currentLines / (float)totalLines * 100);

                if (percentComplete > highestPercentageReached)
                {
                    highestPercentageReached = percentComplete;
                    worker.ReportProgress(percentComplete);
                }
            }
            sw.Close();
            sr.Close();

            if (_deleteLog)
            {
                DeleteLog();
            }
        }

        private void DeleteLog()
        {
            File.Delete(_logPath + "\\" + _logFile);
        }

        private int[] splitGuid(string myGuid)
        {
            int mobtype=0, npcnum=0, spawncount=0;

            if (myGuid.Length == 18 && myGuid.StartsWith("0x"))
            {
                mobtype = int.Parse(myGuid.Substring(2, 4), System.Globalization.NumberStyles.HexNumber);
                npcnum = int.Parse(myGuid.Substring(6, 6), System.Globalization.NumberStyles.HexNumber);
                spawncount = int.Parse(myGuid.Substring(12, 6), System.Globalization.NumberStyles.HexNumber);
            }

            return new int[] { mobtype, npcnum, spawncount };
        }

        private string joinGuid(int[] toJoin)
        {
            string outputGuid = "";

            if (toJoin.Length == 3)
            {
                outputGuid += toJoin[0].ToString("X");
                outputGuid += toJoin[1].ToString("X");
                outputGuid += toJoin[2].ToString("X");
            }

            return outputGuid;
        }

        private void BuildBossHash()
        {
            // ---------------
            // Karazhan Bosses
            // ---------------

            bosses.Add("attumen",new Hashtable());
            bosses["attumen"].Add("longname", "Attumen the Huntsman");
            bosses["attumen"].Add("mobstart", new string[]{ "16151", "Midnight" });
            bosses["attumen"].Add("mobcontinue", new string[]{ "15550", "16151", "Attumen the Huntsman", "Midnight" });
            bosses["attumen"].Add("mobend", new string[]{ "15550", "Attumen the Huntsman" });
            bosses["attumen"].Add("timeout", 15);

            bosses.Add("moroes", new Hashtable());
            bosses["moroes"].Add("longname", "Moroes");
            bosses["moroes"].Add("mobstart", new string[]{ "15687", "Moroes" });
            bosses["moroes"].Add("mobcontinue", new string[]{ "15687", "Moroes" });
            bosses["moroes"].Add("mobend", new string[]{ "15687", "Moroes" });
            bosses["moroes"].Add("timeout", 20);

            bosses.Add("maiden", new Hashtable());
            bosses["maiden"].Add("longname", "Maiden of Virtue");
            bosses["maiden"].Add("mobstart", new string[] { "15687", "Maiden of Virtue" });
            bosses["maiden"].Add("mobcontinue", new string[] { "15687", "Maiden of Virtue" });
            bosses["maiden"].Add("mobend", new string[] { "15687", "Maiden of Virtue" });
            bosses["maiden"].Add("timeout", 20);

            bosses.Add("crone", new Hashtable());
            bosses["crone"].Add("longname", "Opera (Wizard of Oz)");
            bosses["crone"].Add("mobstart", new string[] { "17535", "17548", "17543", "17547", "17546", "Dorothee", "Tito", "Strawman", "Tinhead", "Roar" });
            bosses["crone"].Add("mobcontinue", new string[] { "17535", "17548", "17543", "17547", "17546", "18168", "Dorothee", "Tito", "Strawman", "Tinhead", "Roar", "The Crone" });
            bosses["crone"].Add("mobend", new string[] { "18168", "The Crone" });
            bosses["crone"].Add("timeout", 20);

            bosses.Add("romulo", new Hashtable());
            bosses["romulo"].Add("longname", "Opera (Romulo and Julianne)");
            bosses["romulo"].Add("mobstart", new string[] { "17534", "Julianne" });
            bosses["romulo"].Add("mobcontinue", new string[] { "17533", "17534", "Romulo", "Julianne" });
            bosses["romulo"].Add("mobend", new string[] { "17533", "17534" });
            bosses["romulo"].Add("endall", 1);
            bosses["romulo"].Add("timeout", 20);

            bosses.Add("bbw", new Hashtable());
            bosses["bbw"].Add("longname", "Opera (Red Riding Hood)");
            bosses["bbw"].Add("mobstart", new string[] { "17521", "The Big Bad Wolf" });
            bosses["bbw"].Add("mobcontinue", new string[] { "17521", "The Big Bad Wolf" });
            bosses["bbw"].Add("mobend", new string[] { "17521", "The Big Bad Wolf" });
            bosses["bbw"].Add("timeout", 20);

            bosses.Add("nightbane", new Hashtable());
            bosses["nightbane"].Add("longname", "Nightbane");
            bosses["nightbane"].Add("mobstart", new string[] { "17225", "Nightbane" });
            bosses["nightbane"].Add("mobcontinue", new string[] { "17225", "17261", "Nightbane", "Restless Skeleton" });
            bosses["nightbane"].Add("mobend", new string[] { "17225", "Nightbane" });
            bosses["nightbane"].Add("timeout", 30);

            bosses.Add("curator", new Hashtable());
            bosses["curator"].Add("longname", "The Curator");
            bosses["curator"].Add("mobstart", new string[] { "15691", "The Curator" });
            bosses["curator"].Add("mobcontinue", new string[] { "15691", "The Curator" });
            bosses["curator"].Add("mobend", new string[] { "15691", "The Curator" });
            bosses["curator"].Add("timeout", 20);

            bosses.Add("shade", new Hashtable());
            bosses["shade"].Add("longname", "Shade of Aran");
            bosses["shade"].Add("mobstart", new string[] { "16524", "Shade of Aran" });
            bosses["shade"].Add("mobcontinue", new string[] { "16524", "Shade of Aran" });
            bosses["shade"].Add("mobend", new string[] { "16524", "Shade of Aran" });
            bosses["shade"].Add("timeout", 20);

            bosses.Add("illhoof", new Hashtable());
            bosses["illhoof"].Add("longname", "Terestian Illhoof");
            bosses["illhoof"].Add("mobstart", new string[] { "15688", "Terestian Illhoof" });
            bosses["illhoof"].Add("mobcontinue", new string[] { "15688", "Terestian Illhoof" });
            bosses["illhoof"].Add("mobend", new string[] { "15688", "Terestian Illhoof" });
            bosses["illhoof"].Add("timeout", 20);

            bosses.Add("netherspite", new Hashtable());
            bosses["netherspite"].Add("longname", "Netherspite");
            bosses["netherspite"].Add("mobstart", new string[] { "15689", "Netherspite" });
            bosses["netherspite"].Add("mobcontinue", new string[] { "15689", "Netherspite" });
            bosses["netherspite"].Add("mobend", new string[] { "15689", "Netherspite" });
            bosses["netherspite"].Add("timeout", 45);

            bosses.Add("prince", new Hashtable());
            bosses["prince"].Add("longname", "Prince Malchezaar");
            bosses["prince"].Add("mobstart", new string[] { "15690", "Prince Malchezaar" });
            bosses["prince"].Add("mobcontinue", new string[] { "15690", "Prince Malchezaar" });
            bosses["prince"].Add("mobend", new string[] { "15690", "Prince Malchezaar" });
            bosses["prince"].Add("timeout", 20);

            foreach (string bossname in bosses.Keys)
            {
                startIDs.Add(bossname, (string[])bosses[bossname]["mobstart"]);
                contIDs.Add(bossname, (string[])bosses[bossname]["mobcontinue"]);
                endIDs.Add(bossname, (string[])bosses[bossname]["mobend"]);
            }
        }
    }
}
